package ws

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
	"math/rand"
	"net/http"
	"oa-rest/middleware"
	"sync"
	"time"

	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true // 允许所有跨域请求，生产环境应限制
	},
}

// Client 代表一个WebSocket客户端
type Client struct {
	conn      *websocket.Conn
	send      chan []byte
	ClientID  string    // 连接ID，可以是随机生成，用于标识TCP连接本身
	AgentID   string    // 客服唯一身份ID，由业务系统提供（如工号），对应到系统就是username，也就是登录帐号
	IsOnline  bool      // 在线状态
	LoginTime time.Time // 登录时间
	mutex     sync.RWMutex
}

// SetOnlineStatus 安全地设置在线状态
func (c *Client) SetOnlineStatus(online bool) {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	c.IsOnline = online
}

// GetOnlineStatus 安全地获取在线状态
func (c *Client) GetOnlineStatus() bool {
	c.mutex.RLock()
	defer c.mutex.RUnlock()
	return c.IsOnline
}

// Hub 管理所有客户端
type Hub struct {
	clients    map[*Client]bool
	broadcast  chan []byte
	register   chan *Client
	unregister chan *Client
	agentMap   map[string]*Client // 新增：AgentID -> Client 的映射，用于点对点发送
	mutex      sync.RWMutex
}

var hub = &Hub{
	broadcast:  make(chan []byte),
	register:   make(chan *Client),
	unregister: make(chan *Client),
	clients:    make(map[*Client]bool),
	agentMap:   make(map[string]*Client), // 初始化映射
}

func (h *Hub) run() {
	for {
		select {
		case client := <-h.register:
			h.mutex.Lock()
			h.clients[client] = true
			h.mutex.Unlock()
			log.Printf("新客户端 %s 已链接，等待认证。", client.ClientID)

		case client := <-h.unregister:
			h.mutex.Lock()
			// 检查客户端是否存在，防止因多次发送 unregister 信号而重复执行关闭逻辑
			if _, ok := h.clients[client]; ok {
				// 从 clients map 中删除
				delete(h.clients, client)

				// 从 agentMap 中删除 (逻辑不变，且非常健壮)
				if client.AgentID != "" {
					if storedClient, exists := h.agentMap[client.AgentID]; exists && storedClient == client {
						delete(h.agentMap, client.AgentID)
						log.Printf("客服 %s (来自客户端 %s) 已从 agent map 中移除。", client.AgentID, client.ClientID)
					}
				}

				// 关闭 channel，这是它唯一应该被关闭的地方！
				close(client.send)
				log.Printf("客户端 %s 的资源已清理。", client.ClientID)
			}
			h.mutex.Unlock()

		case message := <-h.broadcast:
			h.mutex.Lock()
			for client := range h.clients {
				select {
				case client.send <- message:
				default:
					// 消息通道已满，客户端无法接收消息。
					// 此时不应该关闭连接，也不应该在这里执行清理。
					// 只需要将其从 h.clients 广播列表中移除即可。
					// 客户端自身的 readPump 会因为心跳失败等原因自动断开，
					// 从而触发 unregister 逻辑，最终完成完整的资源清理。
					log.Printf("客户端 %s 的消息通道已满，已从广播组移除。", client.ClientID)
					delete(h.clients, client)
				}
			}
			h.mutex.Unlock()
		}
	}
}

func (c *Client) readPump() {
	defer func() {
		hub.unregister <- c
		c.conn.Close()
	}()

	// 设置初始读超时，要求客户端在连接后尽快认证
	c.conn.SetReadDeadline(time.Now().Add(10 * time.Second))

	for {
		_, message, err := c.conn.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				log.Printf("从客户端：%s读取错误: %v", c.ClientID, err)
			}
			break
		}

		log.Printf("收到原始消息: %s", string(message))
		//// 首先尝试解析消息是否为字符串格式
		//var rawMessageString string
		//if err := json.Unmarshal(message, &rawMessageString); err == nil {
		//	// 如果成功解析为字符串，说明消息是字符串化的JSON
		//	// 现在需要把这个字符串再解析为JSON对象
		//	message = []byte(rawMessageString)
		//	log.Printf("解析出字符串化JSON: %s", rawMessageString)
		//}

		var incomingMsg IncomingMessage
		if err := json.Unmarshal(message, &incomingMsg); err != nil {
			log.Printf("消息格式错误: %v, msg: %s", err, message)
			continue
		}

		// 处理不同类型的消息
		switch incomingMsg.Type {
		case MessageTypeAuth:
			// 如果已经认证过，则忽略后续的认证消息
			if c.AgentID != "" {
				log.Printf("客户端 %s 重复认证尝试", c.ClientID)
				continue
			}

			token, ok := incomingMsg.Data["token"].(string)
			if !ok {
				log.Printf("认证消息格式错误: %v", err)
				c.send <- []byte(`{"type": "error", "message": "无效的认证格式"}`)
				continue
			}

			// 验证Token，获取AgentID
			claims, err := middleware.ParseToken(token) // 您需要实现这个函数
			if err != nil {
				log.Printf("Token验证失败: %v", err)
				c.send <- []byte(`{"type": "error", "message": "认证失败"}`)
				// 认证失败，关闭连接
				c.conn.Close()
				return
			}

			agentID := claims.Username

			hub.mutex.Lock()
			if oldClient, exists := hub.agentMap[agentID]; exists {
				log.Printf("客服 %s 重复登录，关闭旧连接%s", agentID, oldClient.ClientID)
				oldClient.send <- []byte(`{"type": "force_logout", "message": "已在其他地方登录。"}`)

				//close(oldClient.send)          // 关闭旧连接的通道
				oldClient.conn.Close()         // 关闭旧连接的Socket
				delete(hub.clients, oldClient) // 从广播组移除
			}

			// 认证成功，绑定AgentID
			c.AgentID = agentID
			c.SetOnlineStatus(true)
			hub.agentMap[agentID] = c
			hub.mutex.Unlock()

			// 重置读超时时间为心跳间隔
			c.conn.SetReadDeadline(time.Time{})
			log.Printf("客服 %s 认证成功, clientId： %s", agentID, c.ClientID)
			c.send <- []byte(`{"type": "auth_success", "message": "认证成功"}`)

		case MessageTypePing:
			// 处理心跳
			c.send <- []byte(`{"type": "pong"}`)

		default:
			// 处理其他业务消息，但要求必须已认证
			if c.AgentID == "" {
				log.Printf("收到未认证客户端的消息")
				c.send <- []byte(`{"type": "error", "message": "请先认证"}`)
				continue
			}
			// 在这里处理其他类型的业务消息...
			log.Printf("收到来自客服 %s 的消息: %s", c.AgentID, incomingMsg.Data)
		}
	}
}

func (c *Client) writePump() {
	ticker := time.NewTicker(30 * time.Second)
	defer func() {
		ticker.Stop()
		c.conn.Close()
	}()

	for {
		select {
		case message, ok := <-c.send:
			c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if !ok {
				c.conn.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}

			w, err := c.conn.NextWriter(websocket.TextMessage)
			if err != nil {
				return
			}
			w.Write(message)

			if err := w.Close(); err != nil {
				return
			}

		case <-ticker.C:
			c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
				return
			}
		}
	}
}

func serveWs(w http.ResponseWriter, r *http.Request) {
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("升级WebSocket失败:", err)
		return
	}
	log.Printf("%s socket已链接！", conn.RemoteAddr())

	client := &Client{
		conn:      conn,
		send:      make(chan []byte, 256),
		ClientID:  generateClientID(), // 唯一连接ID
		AgentID:   "",                 // 初始为空，等待认证消息
		IsOnline:  false,              // 未认证前为离线状态
		LoginTime: time.Now(),
	}

	hub.register <- client

	go client.writePump()
	go client.readPump()
}

// BroadcastMessage 广播消息给所有客户端
func BroadcastMessage(message string) {
	hub.broadcast <- []byte(message)
}

// SendToAgent 向指定客服发送消息
func SendToAgent(agentID string, message string) error {
	hub.mutex.RLock()
	defer hub.mutex.RUnlock()

	client, exists := hub.agentMap[agentID]
	if !exists {
		return fmt.Errorf("客服 %s 不在线", agentID)
	}

	// 检查连接是否在线
	if !client.GetOnlineStatus() {
		return fmt.Errorf("客服 %s 处于离线状态", agentID)
	}

	// 非阻塞发送，如果通道满则视为失败
	select {
	case client.send <- []byte(message):
		return nil
	default:
		return fmt.Errorf("客服 %s 的消息通道已满", agentID)
	}
}

// 定时发送示例消息
func startExampleBroadcaster() {
	ticker := time.NewTicker(5 * time.Second)
	go func() {
		for range ticker.C {
			message := map[string]interface{}{
				"type":    "system",
				"message": "系统时间: " + time.Now().Format("2006-01-02 15:04:05"),
				"time":    time.Now().Unix(),
			}
			jsonMsg, _ := json.Marshal(message)

			// 这里可以转换为JSON发送
			BroadcastMessage(string(jsonMsg))
		}
	}()
}

// 生成客户端ID
func generateClientID() string {
	return "client_" + time.Now().Format("20060102150405") + "_" + randomString(8)
}

// 优化后的随机字符串生成函数
func randomString(length int) string {
	// 定义用于生成随机字符串的字符集
	const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"

	// 初始化一个全局唯一的随机数生成器
	// 每次程序启动时使用当前时间戳作为种子，以确保每次运行的结果都不同
	var seededRand *rand.Rand = rand.New(
		rand.NewSource(time.Now().UnixNano()))

	// 创建一个 byte 数组来存放结果
	b := make([]byte, length)

	// 循环并从字符集中随机选择字符填充数组
	for i := range b {
		b[i] = charset[seededRand.Intn(len(charset))]
	}

	// 将 byte 数组转换为 string 并返回
	return string(b)
}

func Start() {
	go hub.run()
	//startExampleBroadcaster()

	// 初始化Gin路由
	router := gin.Default()

	// 允许跨域
	router.Use(func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")

		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}

		c.Next()
	})

	// WebSocket连接端点
	router.GET("/ws", func(c *gin.Context) {
		serveWs(c.Writer, c.Request)
	})

	// 广播消息端点
	router.POST("/ws/broadcast", func(c *gin.Context) {
		var msg Message

		if err := c.ShouldBindJSON(&msg); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "无效的请求"})
			return
		}

		jsonMsg, _ := json.Marshal(msg)

		BroadcastMessage(string(jsonMsg))
		c.JSON(http.StatusOK, gin.H{"message": "消息已广播"})
	})

	// 设置客服状态 (在线/离线)
	router.POST("/ws/agent-status", func(c *gin.Context) {
		var req struct {
			AgentID string `json:"agent_id" binding:"required"`
			Status  bool   `json:"status"` // true:在线, false:离线
		}

		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		hub.mutex.RLock()
		client, exists := hub.agentMap[req.AgentID]
		hub.mutex.RUnlock()

		if !exists {
			c.JSON(http.StatusNotFound, gin.H{"error": "客服连接不存在"})
			return
		}

		client.SetOnlineStatus(req.Status)
		c.JSON(http.StatusOK, gin.H{"message": "状态更新成功", "status": req.Status})
	})

	// 获取所有客服状态
	router.GET("/ws/agents-status", func(c *gin.Context) {
		hub.mutex.RLock()
		defer hub.mutex.RUnlock()

		statusList := make([]map[string]interface{}, 0, len(hub.agentMap))
		for agentID, client := range hub.agentMap {
			statusList = append(statusList, map[string]interface{}{
				"agent_id":   agentID,
				"is_online":  client.GetOnlineStatus(),
				"login_time": client.LoginTime,
				"client_id":  client.ClientID,
			})
		}

		c.JSON(http.StatusOK, gin.H{"agents": statusList})
	})

	// 向特定客服发送消息
	router.POST("/ws/send-to-agent", func(c *gin.Context) {
		var request struct {
			AgentID string `json:"agent_id" binding:"required"`
			Message string `json:"message" binding:"required"`
		}

		if err := c.ShouldBindJSON(&request); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		// 将消息转换为JSON或您需要的格式
		msg := map[string]interface{}{
			"type":      "point_to_point",
			"message":   request.Message,
			"timestamp": time.Now().Unix(),
		}
		jsonMsg, _ := json.Marshal(msg)

		err := SendToAgent(request.AgentID, string(jsonMsg))
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		c.JSON(http.StatusOK, gin.H{"message": "消息已发送"})
	})

	log.Println("WebSocket服务器启动在 :8081")
	log.Println("可用端点:")
	log.Println("  GET  /ws        - WebSocket连接")
	log.Println("  POST /ws/broadcast - 广播消息")
	log.Println("  GET  /ws/stats     - 获取统计信息")

	router.Run(":8081")

}
